using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace IUPUI.StellarResults.Client.UIElements
{
	/// <summary>
	/// A view of a <see cref="Simulation"/>.
	/// </summary>
	public partial class SimulationView : UserControl
	{
		#region Private Properties
		private bool m_IsInitialized = false;
		private Simulation m_Simulation = null;
		private EventHandler<ININ.EventArgs<Simulation>> m_SimulationChanged;
		private bool m_MapViewLoaded = false;
		private MapView m_MapView = null;
		private bool m_DataViewLoaded = false;
		private DataView m_DataView = null;
		#endregion Private Properties

		/// <summary>
		/// Occurs when [simulation changed].
		/// </summary>
		public event EventHandler<ININ.EventArgs<Simulation>> SimulationChanged
		{
			add
			{
				m_SimulationChanged += value;
			}
			remove
			{
				m_SimulationChanged -= value;
			}
		}

		#region Public Properties
		/// <summary>
		/// Gets a value indicating whether this instance is initialized.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is initialized; otherwise, <c>false</c>.
		/// </value>
		public bool IsInitialized
		{
			get
			{
				return m_IsInitialized;
			}
		}

		/// <summary>
		/// Gets or sets the simulation.
		/// </summary>
		/// <value>The simulation.</value>
		public Simulation Simulation
		{
			get
			{
				return m_Simulation;
			}
			set
			{
				if (m_Simulation != value)
				{
					m_Simulation = value;
					OnSimulationChanged();
				}
			}
		}

		/// <summary>
		/// Gets the astronomical timer.
		/// </summary>
		/// <value>The astronomical timer.</value>
		public AstronomicalTimer AstronomicalTimer
		{
			get
			{
				return m_AstronomicalTimerControl.AstronomicalTimer;
			}
		}
		#endregion Public Properties

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationView"/> class.
		/// </summary>
		public SimulationView()
		{
			InitializeComponent();
			m_IsInitialized = true;


			// TODO: Removed map page for now, until it is complete
			m_MainTabControl.TabPages.Remove(m_MapTabPage);

			if (!DesignMode)
			{
				m_AstronomicalTimerControl.AstronomicalTimer.CurrentDateTimeChanged +=
					new EventHandler<ININ.EventArgs<DateTime>>(AstronomicalTimer_CurrentDateTimeChanged);
				m_AstronomicalTimerControl.AstronomicalTimer.EnabledChanged += 
					new EventHandler<ININ.EventArgs<bool>>(AstronomicalTimer_EnabledChanged);
				m_AstronomicalTimerControl.AstronomicalTimer.SpeedChanged += 
					new EventHandler<ININ.EventArgs<DateTimeInterval>>(AstronomicalTimer_SpeedChanged);
				LoadSimulation();
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationView"/> class.
		/// </summary>
		public SimulationView(
			IContainer container)
			: this()
		{
			container.Add(this);
		}
		#endregion Constructors

		#region Public Methods
		/// <summary>
		/// Prints this instance.
		/// </summary>
		public void Print()
		{
			m_MainTabControl.SelectedTab = m_DataTabPage;
			m_DataView.Print();
		}

		/// <summary>
		/// Prints the preview.
		/// </summary>
		public void PrintPreview()
		{
			m_MainTabControl.SelectedTab = m_DataTabPage;
			m_DataView.PrintPreview();
		}
		#endregion Public Methods

		/// <summary>
		/// Handles the CurrentDateTimeChanged event of the AstronomicalTimer control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="ININ.EventArgs&lt;System.DateTime&gt;"/> instance containing the event data.</param>
		private void AstronomicalTimer_CurrentDateTimeChanged(object sender, ININ.EventArgs<DateTime> e)
		{
			if (e.Data != DateTime.MinValue)
			{
				TakeReadings(e.Data);
				m_ObservatoriesViewerControl.CurrentDateTimeUTC = e.Data;
			}
		}

		/// <summary>
		/// Takes the readings.
		/// </summary>
		private void TakeReadings(DateTime dateTimeUTC)
		{
			if (m_Simulation != null && m_Simulation.Observatories.Count > 0)
			{
				AstronomicalObject[] astronomicalObjects = m_Simulation.AstronomicalObjects.ToArray();

				// Get readings for all observatories
				foreach (Observatory observatory in m_Simulation.Observatories)
				{
					// Get readings for the current datetime
					Reading[] readings = observatory.TakeReadings(
						astronomicalObjects,
						m_Simulation.ObservationType,
						dateTimeUTC,
						m_Simulation.StartDateTime);
				}
			}
		}

		/// <summary>
		/// Handles the EnabledChanged event of the AstronomicalTimer control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="ININ.EventArgs&lt;System.Boolean&gt;"/> instance containing the event data.</param>
		private void AstronomicalTimer_EnabledChanged(object sender, ININ.EventArgs<bool> e)
		{
			m_Simulation.IsSimulationRunning = e.Data;
		}

		/// <summary>
		/// Handles the SpeedChanged event of the AstronomicalTimer control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="ININ.EventArgs&lt;IUPUI.StellarResults.DateTimeInterval&gt;"/> instance containing the event data.</param>
		private void AstronomicalTimer_SpeedChanged(object sender, ININ.EventArgs<DateTimeInterval> e)
		{
			ChangePositionTimerOnObservatories(e.Data);
		}

		/// <summary>
		/// Changes the position timer on observatories.
		/// </summary>
		/// <param name="interval">The interval.</param>
		private void ChangePositionTimerOnObservatories(
			DateTimeInterval interval)
		{
			if (m_Simulation != null)
			{
				// If the interval is null, then get it from the timer
				if(interval == null)
				{
					interval = new DateTimeInterval(
						m_AstronomicalTimerControl.AstronomicalTimer.Speed.Value,
						m_AstronomicalTimerControl.AstronomicalTimer.Speed.Unit);
				}

				foreach (Observatory observatory in m_Simulation.Observatories)
				{
					observatory.ChangePositionInterval = interval;
				}
			}
		}

		/// <summary>
		/// Called when [simulation changed].
		/// </summary>
		protected virtual void OnSimulationChanged()
		{
			LoadSimulation();

			m_DataViewLoaded = false;
			m_MapViewLoaded = false;
			LoadTabPage();

			if (m_SimulationChanged != null)
			{
				m_SimulationChanged(this, new ININ.EventArgs<Simulation>(m_Simulation));
			}
		}

		/// <summary>
		/// Loads the simulation.
		/// </summary>
		private void LoadSimulation()
		{
			if (m_IsInitialized && !this.DesignMode)
			{
				if (m_Simulation != null)
				{
					ChangePositionTimerOnObservatories(null);

					m_ObservatoriesViewerControl.CurrentDateTimeUTC =
						m_AstronomicalTimerControl.AstronomicalTimer.CurrentDateTimeUTC =
						m_Simulation.StartDateTime;
				}

				if (m_Simulation != null)
				{
					m_LegendLabel.Text =
						String.Format(
							Properties.Resources.AstronomicalObjectLegendLabel,
							m_Simulation.AstronomicalObjects.Count.ToString());
				}
				else
				{
					m_LegendLabel.Text =
						String.Format(
							Properties.Resources.AstronomicalObjectLegendLabel,
							"0");
				}

				m_AstronomicalObjectsLegendControl.Simulation =
					m_Simulation;		
				m_ObservatoriesViewerControl.Simulation =
					m_Simulation;
				m_ReadingsView.Simulation =
					m_Simulation;
			}
		}

		/// <summary>
		/// Handles the SelectedIndexChanged event of the m_MainTabControl control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void m_MainTabControl_SelectedIndexChanged(object sender, EventArgs e)
		{
			LoadTabPage();
		}

		/// <summary>
		/// Loads the tab page.
		/// </summary>
		private void LoadTabPage()
		{
			switch (m_MainTabControl.SelectedTab.Name)
			{
				case "m_ObservatoriesTabPage":
					break;
				case "m_MapTabPage":
					if (!m_MapViewLoaded)
					{
						LoadMapTabPage();
					}
					break;
				case "m_DataTabPage":
					if (!m_DataViewLoaded)
					{
						LoadDataTabPage();
					}
					break;
			}
		}

		/// <summary>
		/// Loads the map tab page.
		/// </summary>
		private void LoadMapTabPage()
		{
			m_MapTabPage.Controls.Clear();
			m_MapView = new MapView(this.components, m_Simulation);
			m_MapView.Dock = DockStyle.Fill;
			m_MapTabPage.Controls.Add(m_MapView);
		}

		/// <summary>
		/// Loads the data tab page.
		/// </summary>
		private void LoadDataTabPage()
		{
			m_DataTabPage.Controls.Clear();
			m_DataView = new DataView(this.components, m_Simulation);
			m_DataView.Dock = DockStyle.Fill;
			m_DataTabPage.Controls.Add(m_DataView);
		}
	}
}
